Skip to content

fix(build): derive Astryx surface inventory from @astryxdesign/core - #3883

Open
liuxiaocs7 wants to merge 1 commit into
apache:mainfrom
liuxiaocs7:liuxiaocs7/fix-build-astryx-surface-inventory-cannot-see-mo
Open

fix(build): derive Astryx surface inventory from @astryxdesign/core#3883
liuxiaocs7 wants to merge 1 commit into
apache:mainfrom
liuxiaocs7:liuxiaocs7/fix-build-astryx-surface-inventory-cannot-see-mo

Conversation

@liuxiaocs7

@liuxiaocs7 liuxiaocs7 commented Aug 26, 2026

Copy link
Copy Markdown
Member

Summary

The file-level Astryx surface inventory (docs/astryx-surface-file-inventory.md, generated by scripts/generate-astryx-surface-inventory.mjs and enforced by scripts/check-astryx-surface-inventory.mjs) could not see most of the design system, for two reasons — both in that one file:

  1. The known-component set was a hand-maintained 47-name list while @astryxdesign/core ships ~194 components, so Timestamp, ChatMessage, Thumbnail, and others were invisible (0 rows) even though packages/ui/src/chat-turn.tsx renders them. Removing such a component left a row byte-identical, so the gate saw nothing (same root cause as Astryx surface inventory check is one-directional and not wired into CI #3064).
  2. Severity only recognized raw button/input/select, so a hand-rolled twin of a shipped component scored aligned.

This PR:

  • Derives the Astryx component set from the shipped .d.ts (dist/index.d.ts + each export * from './Dir'). The derivation is fail-closed: an unresolved barrel target, a version that disagrees with the pinned dependency, or a parse below a floor / missing a key component aborts the run — never a silent partial set. The generated doc header records @astryxdesign/core@<version> and the export count.
  • Derives the @maka/ui → Astryx re-export map from the barrel export graph (packages/ui/src/index.ts, resolving export * / aliased re-export chains) instead of a hand-maintained list, so the "Astryx used" column is a true record.
  • Adds a conservative reimplementation tier: a public @maka/ui export whose name shadows a shipped Astryx component but is defined locally (not a re-export). Neutral wording — a review signal, not a claim of semantic re-implementation. It flags 0 files on the current tree (no false positives).
  • Fixes CI: the npm ci install step now runs on astryx_surface, so an inventory-doc-only PR installs dependencies before the generator runs; guarded by a new scripts/ci-test-plan.test.mjs assertion.

Fixes #3868

Verification

Ran locally (Node 24, @astryxdesign/core@0.5.0):

  • npm run astryx:surface-inventory:writeastryx @0.5.0: blocker=0 reimplementation=0 polish=1 aligned=213
  • npm run astryx:surface-inventory (coverage gate) → coverage: ok (214 files, 1 exclusions)
  • npm run astryx:surface-inventory:test → 9 pass (derivation version/floor/key-components; barrel re-export + nested export * + local-shadow detection; fail-closed on unresolved target; severity cases)
  • node --test scripts/ci-test-plan.test.mjs → all pass (incl. the new install-dependencies-covers-astryx_surface assertion)
  • biome check on the changed scripts + package.json, and node scripts/asf-license-headers.mjs check → clean

Not run: full npm run build / repo-wide typecheck. The change is confined to build-tooling scripts and their generated docs (the .mjs scripts are outside the workspace tsc graph).

Review response (thanks @codex)

  • P1 — CI installs deps for inventory-only PRs: npm ci now gates on astryx_surface; regression test added in ci-test-plan.test.mjs.
  • P1 — reimplementation false positives: redesigned from name-matching to public-export shadowing with neutral wording. The prior two hits were not real: markdown.tsx's Markdown is not publicly exported, and module-hub-selector.tsx's Selector is private (the public Selector is a direct Astryx re-export). Now 0 findings, no false positives.
  • P2 — @maka/ui re-exports auto-derived: the hand-written list is removed; the map is resolved from the barrel export graph (35 names vs the old 9).
  • P2 — fail-closed declaration parsing: version-vs-pin check, minimum-count and key-component assertions, and a hard error on any unresolved barrel target. (The TS compiler API was not adopted: this repo's typescript@7 is the Go-native port — platform binaries, no classic ts.createSourceFile JS API — so a hardened lightweight parser with explicit fail-closed checks is used instead.)
  • P3 — version recorded: the loader returns { version, components } and the doc header states the version + export count.

AI use

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: Claude Code (Claude Opus 4.8) — analysis, design of the derivation/detection, the script and test changes, and repository verification. The commit carries a Generated-by trailer.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above
  • No

@liuxiaocs7
liuxiaocs7 force-pushed the liuxiaocs7/fix-build-astryx-surface-inventory-cannot-see-mo branch from 5439e35 to 329a92b Compare August 26, 2026 08:09

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this head and found no blocking issues.

Derives Astryx surface inventory from installed package .d.ts (fail-closed on unparsable, no silent fallback), with correct wrapper/re-implementation classification; hosted test/package/windows_recovery/audit/owner all SUCCESS.

No P0-P3.

简体中文该头无阻断。

Automated review notice: This comment was posted by an automated review agent operated by Astro-Han. It is not an independent human review and does not replace one.

@M4n5ter
M4n5ter force-pushed the liuxiaocs7/fix-build-astryx-surface-inventory-cannot-see-mo branch from 329a92b to 47a2dc2 Compare August 26, 2026 08:37

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this head and found no blocking issues.

Drift from 5439e35 to 47a2dc2 is pure rebase (includes #3280); inventory derivation logic unchanged. Hosted test: FAILURE on e2e/workhub-layout is unrelated flake (Desktop E2E, not this PR's scope).

No P0-P3.

简体中文该头为纯 rebase,无新增阻断。

Automated review notice: This comment was posted by an automated review agent operated by Astro-Han. It is not an independent human review and does not replace one.

@liuxiaocs7
liuxiaocs7 force-pushed the liuxiaocs7/fix-build-astryx-surface-inventory-cannot-see-mo branch from 47a2dc2 to 78a6335 Compare August 26, 2026 09:41
@M4n5ter
M4n5ter force-pushed the liuxiaocs7/fix-build-astryx-surface-inventory-cannot-see-mo branch from 78a6335 to 1397483 Compare August 26, 2026 09:58
@liuxiaocs7
liuxiaocs7 force-pushed the liuxiaocs7/fix-build-astryx-surface-inventory-cannot-see-mo branch from 1397483 to ba1e061 Compare August 26, 2026 18:10

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What this PR does

The generated docs/astryx-surface-file-inventory.md could not see most of the design system, for two reasons living in scripts/generate-astryx-surface-inventory.mjs: the known-component set was a hand-maintained 47-name list while @astryxdesign/core ships ~190 components (so Timestamp, ChatMessage, Thumbnail and friends appeared zero times across 213 rows even where they are imported and rendered), and severity only recognized raw button/input/select. This derives the component set by parsing the installed declarations — dist/index.d.ts plus each export * from './Dir' — and adds a reimplementation tier for a local component whose name matches a shipped Astryx twin it does not import.

Verdict

Comment review, not a block: 2 × P1, 2 × P2, 1 × P3, inline.

The diagnosis is right and the derivation half is well built — I checked the parser against the real 0.5.0 declarations and could not find a name it should have caught and missed (194 derived; export type blocks skipped, inline type modifiers handled, export interface XProps not mistaken for a component, SCREAMING constants and useX hooks correctly excluded). Output is byte-stable and locale-independent, and the version is exact-pinned in both manifests and the lockfile.

The two P1s are about the other half. One is mechanical: the gate became install-dependent without moving into the install condition, so an inventory-only PR now red-checks with "run npm install". The other is that the new reimplementation tier, on the current tree, produces two false positives and zero true positives — and one of them is exactly the "wrapper that renders the twin" shape the PR says it excludes.

The thread running through it

The PR names its own root cause well: "a generated artifact whose input is hand-maintained drifts in whichever half the author forgets." It then derives one of the two hand-maintained inputs and leaves the other. MAKA_UI_ASTRYX_REEXPORTS (:146) still hand-lists 9 names while packages/ui/src/index.ts re-exports 34, and the same loop at :281-291 now reads the derived set for one decision and the hand set for the other. So the drift is smaller but structurally identical, and 26 files still under-report.

The second thread is that "wrapper that renders the twin" was implemented as a same-file static-import check, which does not match how this repo actually writes wrappers — markdown.tsx reaches its twin through React.lazy across a file boundary. Widening the exclusion to follow a local re-export/lazy hop, or narrowing the tier to names that are unambiguous rather than generic, would both work; shipping it as-is puts wrong advice into an artifact CI enforces.

Mechanics

The conflict with main is only on the generated file (main deleted runtime-host-project-directory-editor.tsx; 214 rows there against 213 here). Rebase plus npm run astryx:surface-inventory:write resolves it — no hand-editing.

This does not make #2645 materially worse: it conflicts on the same file, its resolution is the same single regenerate command before and after, and it touches package-lock.json, so code=true and the P1 install bug does not hit it. It does mean #2645 can no longer resolve by hand-editing rows.

Note (ungraded)

The churn is understated by omission — the body lists the new names and tiers but not that 66 of 213 rows changed content. The stated totals (blocker 0, reimplementation 2, polish 1, aligned 210) reproduce exactly.

AI use: Claude Code assisted with running the generator, comparing the regenerated artifact, and reading the installed @astryxdesign/core declarations; both P1s were re-verified against the exact head by me, and the analysis, grading, and conclusions are my own. The worktree was restored after regeneration.

简体中文

这个 PR 在做什么:生成的 docs/astryx-surface-file-inventory.md 看不见设计系统的大部分,原因有两个都在生成脚本里——已知组件集是手工维护的 47 个名字,而 @astryxdesign/core 实际有约 190 个(于是 TimestampChatMessageThumbnail 这些在 213 行里出现 0 次,哪怕文件真的 import 并渲染了它们);严重度又只认原生 button/input/select。本 PR 改为解析安装版声明文件(dist/index.d.ts 加每个 export * from './Dir')来推导组件集,并新增 reimplementation 档:本地组件名撞上已发布的 Astryx 同名件、且没有 import 它。

结论:comment review,不阻塞,2 × P1 / 2 × P2 / 1 × P3,全部在行内。

诊断是对的,推导那一半也做得扎实——我拿真实的 0.5.0 声明文件核了解析器,找不到应该收进来却漏掉的名字(推导出 194 个;export type 块正确跳过,行内 type 修饰符正确处理,export interface XProps 没被误判成组件,全大写常量和 useX hook 也都正确排除)。输出字节稳定、与 locale 无关,依赖在两个 manifest 和 lockfile 里都精确锁版。

两条 P1 都在另一半。一条是机械问题:这个门槛变成依赖安装了,却没有把 astryx_surface 移进 install 的条件,于是只改生成文件的 PR 现在会红,还配一句误导的 "run npm install"。另一条是新的 reimplementation 档在当前代码树上是 2 个误报、0 个真阳性——而其中一个恰恰就是 PR 自称会排除的"包了一层但渲染的还是同名件"。

贯穿其中的线索:PR 自己把根因写得很准——"输入靠手工维护的生成物,总会在作者忘记的那一半漂移"。但它只推导了两个手工输入中的一个。MAKA_UI_ASTRYX_REEXPORTS:146)仍然手写 9 个名字,而 packages/ui/src/index.ts 实际再导出 34 个;:281-291 同一个循环里,一个判断读推导集、另一个读手工集。漂移变小了,结构完全一样,26 个文件仍在少报。第二条线索是"包一层就排除"被实现成了同文件静态 import 检查,而这个仓库真正的包装写法不是那样——markdown.tsx 是经 React.lazy 跨文件到达同名件的。

机械层面:与 main 的冲突只在生成文件上,rebase 后跑一次 npm run astryx:surface-inventory:write 即可,不需要手改。对 #2645 没有实质加重:同一个文件冲突,解法前后都是同一条重新生成命令,且它动了 package-lock.jsoncode=true,不会踩到上面那条 install 的坑;唯一影响是 #2645 不能再靠手改行来解冲突了。

不计分:改动量在描述里被省略了——正文列了新名字和新档位,但没提 213 行里有 66 行内容发生变化。给出的总计(blocker 0, reimplementation 2, polish 1, aligned 210)能精确复现。

Comment thread .github/workflows/ci.yml
Comment thread scripts/generate-astryx-surface-inventory.mjs Outdated
Comment thread scripts/generate-astryx-surface-inventory.mjs Outdated
Comment thread scripts/generate-astryx-surface-inventory.mjs
Comment thread scripts/generate-astryx-surface-inventory.mjs
@github-actions github-actions Bot added the effort/M Under 500 readable lines label Aug 27, 2026
@liuxiaocs7
liuxiaocs7 force-pushed the liuxiaocs7/fix-build-astryx-surface-inventory-cannot-see-mo branch 2 times, most recently from f362f07 to 1182058 Compare August 27, 2026 05:50
@github-actions github-actions Bot added effort/L Under 1000 readable lines and removed effort/M Under 500 readable lines labels Aug 27, 2026
The file-level Astryx surface inventory could not see most of the design
system. Its known-component set was a hand-maintained 47-name list while
@astryxdesign/core ships ~190 components, so Timestamp, ChatMessage,
Thumbnail and others were invisible — removing such a component from a file
left its inventory row byte-identical and the coverage gate saw nothing.
Severity also recognized only raw button/input/select, so a hand-rolled
replacement for a shipped component scored aligned.

Derive the component set by parsing the installed @astryxdesign/core
declarations (hard error if the package is absent, so the artifact never
silently regenerates with a partial set), add a reimplementation severity
tier for a local component that shadows a shipped twin it does not import,
and regenerate the committed inventory.

Generated-by: Claude Opus 4.8 via Claude Code
@liuxiaocs7
liuxiaocs7 force-pushed the liuxiaocs7/fix-build-astryx-surface-inventory-cannot-see-mo branch from 1182058 to 9652360 Compare August 27, 2026 16:30

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for replacing the hand-maintained Astryx surface map with data derived from the installed package. That is the right ownership boundary and materially reduces drift.

I reviewed exact head 96523606f62a36fe74be19186f369bf7daec3e87. I found one reachable P2 in a reasonable dependency-evolution path: the generator follows only one export * barrel layer. The “nested” fixture currently exercises a direct named export rather than a real Group -> Sub -> Component re-export chain. If Astryx later introduces a second barrel level, valid components can be silently omitted while the broad key/count thresholds still pass.

Could you either traverse the barrel graph recursively with cycle protection and fail-closed handling, or explicitly enforce and test that the installed Astryx package has a one-layer-only export contract? A regression fixture with a genuine multi-level barrel would make the intended boundary executable.

Separately, the current exact head has a failing test check and is conflicting with main, so it will need a refreshed head and green exact-head CI before merge. Those are delivery gates rather than additional code findings.

Review analysis was assisted by Codex and independent @reviewer agents; Astro-Han verified the exact-head implementation, package boundary, reachability, and CI state and owns this review.

中文对照

感谢你把手工维护的 Astryx surface 映射改为从已安装包中推导。这个职责边界是对的,也确实减少了漂移风险。

我审查了当前提交 96523606f62a36fe74be19186f369bf7daec3e87。这里有一个可达的 P2,属于合理的依赖包结构演进路径:生成器目前只会跟随一层 export * barrel。现有的 “nested” fixture 实际测试的是直接命名导出,而不是真正的 Group -> Sub -> Component 多层 re-export。如果 Astryx 以后增加第二层 barrel,合法组件可能会被静默遗漏,而宽泛的 key/数量阈值仍然可能通过。

建议二选一:递归遍历 barrel graph,并处理循环和严格失败;或者明确约束并测试当前安装的 Astryx 包只能有一层导出。最好补一个真正多层 barrel 的回归 fixture,把这个边界变成可执行契约。

另外,当前提交的 test 失败,并且与 main 有冲突;合并前需要刷新 head,并在该 exact head 上跑绿 CI。这些属于交付门槛,不是额外的代码问题。

本次分析由 Codex 和独立的 @reviewer agents 协助;Astro-Han 核验了当前提交的实现、包边界、可达性和 CI 状态,并对本次评审负责。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/L Under 1000 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(build): Astryx surface inventory cannot see most of the design system

2 participants